<template>
  <el-cascader
    v-bind="$attrs"
    v-on="$listeners"
    :size="cascaderOption.size"
    v-model="areaValue"
    :options="areaRange"
    :props="setProps"
    change-on-select
    @visible-change="visibleChange"
    @change="areaChange"
  ></el-cascader>
</template>
<script>
export default {
  props: {
    value: {
      type: Array,
      default: () => {
        return []
      }
    },
    options: {
      type: Object,
      default: () => {
        return {}
      }
    }
  },
  data () {
    return {
      areaRange: [],
      cascaderOption: {
        size: 'small',
        label: 'regionName',
        value: 'id',
        rangeLen: 2 // 判断需要使用的级别  0只使用省 1使用省市 2使用省市区
      },
      areaValue: [],
      isBack: false // 截断回填时使用
    }
  },
  computed: {
    setProps () {
      return {
        label: this.cascaderOption.label,
        value: this.cascaderOption.value
      }
    }
  },
  watch: {
    value (val) {
      // watch中的回填必须只进行一次
      if (val && val.length && !this.isBack) {
        this.getInfo(val)
        this.isBack = true
      }
      // 外部有清除动作时，清除选项值
      if (!(val && val.length)) {
        this.areaValue = val
        this.areaChange(val)
      }
    }
  },
  created () {
    this.cascaderOption = Object.assign({}, this.cascaderOption, this.options)
    // 组件未销毁时，需要在此处做回填
    if (this.value && this.value.length) this.getInfo(this.value)
  },
  methods: {
    getInfo (val) {
      // 必须有效值存在才做回填
      if (val && val.length) {
      // 回填时，针对数组长度拉取接口
        val.forEach(async (e, index) => {
          if (index === 0) {
          // 第一级直接拉取,判断e必须是有效值，防止外部传入['','','']类数组,此类问题找后端的锅，外部要做好判断
            if (e) await this.getAreaRange(this.areaRange, 1)
          } else {
          // 第二级开始查找后拉取对应子级
            if (e) this.getValInfo(e, this.areaRange, true)
          }
        })
        // 加载完数据后再赋值
        this.areaValue = val
      }
    },
    getAreaRange (data, level, pId) {
      const _this = this
      // 直接获取时使用async await返回的是promise，所以暂时只能通过promise来获取数组
      return new Promise(async (resolve, reject) => {
        // 判断是否已拉取过省/市/区列表
        let areaRange =
          data && data.length
            ? data
            : (await _this.$apis.region.getRegionList({
              regionLevel: level,
              pId: pId
            }) || [])
        if (_this.areaValue.length < _this.cascaderOption.rangeLen) {
          // 调用省和市级时，判断children是否存在,不存在则赋初值
          // 判断只有一级和二级的省市做下箭头处理
          let isOneLevel = [2, 3, 10, 23, 3627, 33, 34, 35, 3627, 3633, 3634] // 直辖市，台湾香港澳门和测试数据都只要1级
          let isTowLevel = [] // 2, 3, 10, 23 4个直辖市需要2级就添加到数组中删去上面的
          let pIdIndex = isTowLevel.findIndex(e => { return e === +pId })
          areaRange.forEach(e => {
            let idIndex = isOneLevel.findIndex(p => { return p === +e.id })
            if (pIdIndex === -1 && idIndex === -1) e.children = e.children && e.children.length ? e.children : []
          })
        }
        resolve(areaRange)
      })
    },
    // 获取选项具体值
    getValInfo (val, list, request) {
      let info = {}
      list.forEach(async e => {
        if (val === e[this.cascaderOption.value]) {
          if (request) {
          // 找到后要把子级挂载
            let children = e.children ? await this.getAreaRange(
              e.children,
              +e.regionLevel + 1,
              e.id
            ) : []
            if (children && children.length) {
              this.$set(e, 'children', children)
            } else {
              // 如果子级无值，则删掉子级，避免出现箭头
              this.$delete(e, 'children')
            }
          }
          info = e
        } else if (e.children && e.children.length) {
          // 本级找不到继续到子级查找
          info = this.getValInfo(val, e.children, request)
        }
      })
      return info
    },
    // 选择值
    areaChange (val) {
      if (val.length < this.cascaderOption.rangeLen + 1) this.getValInfo(val[val.length - 1], this.areaRange, true)
      let chooseInfoList = []
      val.forEach(e => {
        chooseInfoList.push(this.getValInfo(e, this.areaRange))
      })
      // 外部值只在这里做输出
      this.$emit('input', val || [])
      this.$emit('change-info', { idArr: val || [], infoArr: chooseInfoList })
    },
    async visibleChange (val) {
      if (val) {
        // 展开时只需判断省级数组的情况，
        // 如果回填过，则在此操作之前已经拉取过所有级别的省市区，
        // 获取方法中已做了判断是否从接口走数据
        this.areaRange = await this.getAreaRange(this.areaRange, 1)
      }
    }
  }
}
</script>
